import { Injectable } from '@angular/core';
import { environment } from '../../environments/environment';
import { HttpClient, HttpHeaders, HttpParams, HttpResponse } from '@angular/common/http';
import { ThreadsCollectStatsAndBoard } from '../model/threads-collect-stats-and-board';
import { catchError } from 'rxjs/operators';
import { ThreadsVo } from '../model/threads-vo';
import { ThreadsFoldVo } from '../model/threads-fold-vo';
import { ThreadsCollectStatsAndReplyVo } from '../model/threads-collect-stats-and-reply-vo';
import { ThreadsCollectStatsVo } from '../model/threads-collect-stats-vo';
import { EntityPageResult } from '../model/entity-page-result';
import { ThreadsCollectBoardVo } from '../model/threads-collect-board-vo';
import { ThreadsAlbumPictureRecordVo } from '../model/threads-album-picture-record-vo';
import { CommonResponseVo } from '../model/common-response-vo';
import { ThreadsCategoryVo } from '../model/threads-category-vo';
import { EMPTY, throwError, of, Observable } from 'rxjs';
import { ThreadsTagRelateVo } from '../model/threads-tag-relate-vo';
import { ThreadsUnionCheckVo } from '../model/threads-union-check-vo';

@Injectable({
  providedIn: 'root'
})
export class ThreadsService {
  private restRequestURI: string = environment.restURI + '/threads';
  /**
   * 话题REST API服务
   */
  constructor(private http: HttpClient) { }
  /**
   * 最近的话题,级联加载话题统计,版块
   * @param size 显示的数量
   */
  public getRecent(size: number = 10): Observable<ThreadsCollectStatsAndBoard[]> {
    let params = new HttpParams().append('size', size + '');

    return this.http.get<ThreadsCollectStatsAndBoard[]>(this.restRequestURI + '/home/recent', { params: params });
  }
  /**
   * 查看指定的话题
   * @param topicId 话题ID
   */
  public get(topicId: number): Observable<ThreadsVo> {
    if (0 >= topicId) {
      return throwError('话题ID非可用值');
    }
    return this.http.get<ThreadsVo>(this.restRequestURI + '/' + topicId);
  }
  /**
   * 查看指定的话题,级联加载版块,版块组
   * @param topicId 话题ID
   * @param boardId 版块ID
   * @param boardGroupId 版块组ID
   */
  public getCascade(topicId: number, boardId: number, boardGroupId: number): Observable<ThreadsFoldVo> {
    if (0 >= boardGroupId) {
      return throwError('版块组ID非可用值');
    }
    if (0 >= boardId) {
      return throwError('版块ID非可用值');
    }
    if (0 >= topicId) {
      return throwError('话题ID非可用值');
    }
    return this.http.get<ThreadsFoldVo>(this.restRequestURI + '/' + topicId + '/fold/' + boardId + '/' + boardGroupId);
  }
  /**
   * 查看指定的话题,级联加载话题统计, 话题内容, 作者
   * @param topicId 话题ID
   * @param scale 图片的尺寸,若为null表示自动
   */
  public getContent(topicId: number, scale: string = '640x360'): Observable<ThreadsCollectStatsAndReplyVo> {
    if (0 >= topicId) {
      return throwError('话题ID非可用值');
    }
    return this.http.get<ThreadsCollectStatsAndReplyVo>(this.restRequestURI + '/' + topicId + '/content/' + scale);
  }
  /**
   * 查看指定话题的封面
   * @param topicId 话题ID
   * @param scale 图片的尺寸,若为null表示自动
   * @returns 成功时返回200(响应的内容中包含解码后的地址),失败时返回404(无具体错误描述)
   */
  public getCover(topicId: number, scale: string = '640x360'): Observable<string> {
    if (0 >= topicId) {
      return of('assets/img/default.poster.bg.jpg');
      //throwError('话题ID非可用值');
    }
    //:/{id}/cover/{scale}
    const headers = new HttpHeaders().set('Content-Type', 'text/plain; charset=utf-8');
    return this.http.get(this.restRequestURI + '/' + topicId + '/cover/' + scale, { headers, responseType: 'text' }).pipe(catchError(err => of('assets/img/default.poster.bg.jpg')));;
  }
  /**
   * 查看指定版块组最近的话题,级联加载话题统计
   * @param boardGroupId 版块组ID
   * @param showSize 显示的数量
   */
  public getRecentForVolumes(boardGroupId: number, showSize: number = 10): Observable<ThreadsCollectStatsVo[]> {
    if (0 >= boardGroupId) {
      return throwError('版块组ID非可用值');
    }
    //:/volume/{volume}/recent & QueryParam
    let params = new HttpParams().append('size', showSize + '');
    return this.http.get<ThreadsCollectStatsVo[]>(this.restRequestURI + '/volume/' + boardGroupId + '/recent', { params: params });
  }
  /**
   * 查看指定版块置顶的话题,级联加载话题统计,最多显示5条
   * @param boardId 版块ID
   */
  public getToped(boardId: number): Observable<ThreadsCollectStatsVo[]> {
    if (0 >= boardId) {
      return throwError('版块ID非可用值');
    }
    //F:/board/{board}/top
    return this.http.get<ThreadsCollectStatsVo[]>(this.restRequestURI + '/board/' + boardId + '/top');
  }
  /**
   * 分页查看指定版块下的话题,级联加载话题统计
   * @param boardId 版块ID
   * @param categoryValue 话题分类的值,("-")所有,("tops")置顶,("goods")精华,("hots")火贴
   * @param page 
   * @param pageSize 
   */
  public getAll(boardId: number, categoryValue: string = '-', page: number = 1, pageSize: number = 20): Observable<EntityPageResult<ThreadsCollectStatsVo>> {
    if (0 >= boardId) {
      return throwError('版块ID非可用值');
    }
    //A:/board/{board}/{category}/{page}/{number}
    let ccc: string = "-";
    if (typeof categoryValue != 'undefined' && categoryValue && "-" !== categoryValue) {
      ccc = categoryValue;
    }
    return this.http.get<EntityPageResult<ThreadsCollectStatsVo>>(this.restRequestURI + '/board/' + boardId + '/' + ccc + '/' + page + '/' + pageSize);
  }
  /**
   * 会员发布的话题,级联加载版块
   * @param memberId 会员ID
   * @param showSize 显示的数量
   */
  public getMemberPublish(memberId: number, showSize: number = 5): Observable<ThreadsCollectBoardVo[]> {
    if (0 >= memberId) {
      return throwError('会员ID非可用值');
    }
    //N:/member/recent/{member}
    let ss = 5;
    if (showSize > 10 || showSize < 1) {
      ss = showSize;
    }
    let params = new HttpParams().append('size', ss + '');
    return this.http.get<ThreadsCollectBoardVo[]>(this.restRequestURI + '/member/recent/' + memberId, { params: params });
  }
  /**
   * 会员回复的话题,级联加载版块
   * @param memberId 会员ID
   * @param showSize 显示的数量
   */
  public getMemberReply(memberId: number, showSize: number = 5): Observable<ThreadsCollectBoardVo[]> {
    if (0 >= memberId) {
      return throwError('会员ID非可用值');
    }
    //L:/member/reply/{member}
    let ss = 5;
    if (showSize > 10 || showSize < 1) {
      ss = showSize;
    }
    let params = new HttpParams().append('size', ss + '');
    return this.http.get<ThreadsCollectBoardVo[]>(this.restRequestURI + '/member/reply/' + memberId, { params: params });
  }
  /**
   * 查看指定像册的图片
   * @param albumId 话题的像册ID
   * @param showSize 显示的数量
   * @param scale 图片的尺寸,若为null表示自动
   * @param defaultValue 不存在时的默认图片
   */
  public getAlbumPictures(albumId: number, showSize: number = 4, scale: string = '640x360', defaultValue: string): Observable<ThreadsAlbumPictureRecordVo[]> {
    if (0 > albumId) { //允许0,没有像册吗
      return throwError('像册ID非可用值');
    }
    if (0 === albumId) {
      return EMPTY;
    }
    //:/album/{album}/pictures
    const httpOptions = {
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded'
      }
    };
    const body = new HttpParams().set('size', showSize + '').set('scale', scale).set('default_value', defaultValue);
    return this.http.post<ThreadsAlbumPictureRecordVo[]>(this.restRequestURI + '/album/' + albumId + '/pictures', body.toString(), httpOptions);
  }
  /**
   * 查看举报的类型
   */
  public reportType(): Observable<CommonResponseVo[]> {
    //:/report/category
    return this.http.get<CommonResponseVo[]>(this.restRequestURI + '/report/category');
  }
  /**
   * 举报话题
   * @param topicId 话题ID
   * @param reportContent 举报的内容
   * @param reportType 举报的类型
   * @param memberId 会员ID
   * @param memberNickname 会员昵称
   * @param token 
   * @param ipAddr 
   * @returns 成功的状态码是200(响应的内容是ThreadsVo),失败的状态:404(表示创建失败),400(前置检查时触发的响应)
   */
  public report(topicId: number, reportContent: string, reportType: number, memberId: number, memberNickname: string, token: string, ipAddr: string): Observable<ThreadsVo> {
    if (0 >= topicId) {
      return throwError('话题ID非可用值');
    }
    if (!reportContent || reportContent.length == 0) {
      return throwError('举报内容非可用值');
    }
    if (0 >= reportType) {
      return throwError('举报类型非可用值');
    }
    if (0 >= memberId) {
      return throwError('暂不支持游客举报话题');
    }
    //:/{id}/report
    const httpOptions = {
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded'
      }
    };
    const body = new HttpParams().set('content', reportContent).set('type', reportType + '').set('member', memberId + '').set('nickname', memberNickname).set('token', token).set('ip', ipAddr);
    return this.http.post<ThreadsVo>(this.restRequestURI + '/' + topicId + '/report', body.toString(), httpOptions);
  }
  /**
   * 是否点过赞了
   * @deprecated
   * @param topicId 话题ID
   * @param memberId 会员ID
   * @returns 成功200(可以点赞),失败417(已经点过赞了)
   */
  public isLiked(topicId: number, memberId: number): Observable<string> {
    //:/{id}/like/member/{member}
    if (0 >= topicId) {
      return throwError('话题ID非可用值');
    }
    if (0 >= memberId) {
      return throwError('会员ID非可用值');
    }
    const headers = new HttpHeaders().set('Content-Type', 'text/plain; charset=utf-8');
    return this.http.get(this.restRequestURI + '/' + topicId + '/like/member/' + memberId, { headers, responseType: 'text' });
  }
  /**
   * 话题点赞
   * @param topicId 话题ID
   * @param memberId 会员ID
   * @param memberNickname 会员昵称
   * @param token 
   * @param ipAddr 
   * @returns 成功的状态码是200,失败的状态:417
   */
  public like(topicId: number, memberId: number, memberNickname: string, token: string, ipAddr: string): Observable<HttpResponse<string>> {
    if (0 >= topicId) {
      return throwError('话题ID非可用值');
    }
    if (0 >= memberId) {
      return throwError('暂不支持游客点赞话题');
    }
    //:/{id}/like
    const httpOptions = {
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded'
      }
    };
    const body = new HttpParams().set('member', memberId + '').set('nickname', memberNickname).set('token', token).set('ip', ipAddr);
    return this.http.put<HttpResponse<string>>(this.restRequestURI + '/' + topicId + '/like', body.toString(), httpOptions);
  }
  /**
   * 是否收藏过了
   * @deprecated
   * @param topicId 话题ID
   * @param memberId 会员ID
   * @returns 成功200(可以收藏),失败417(已经收藏过了)
   */
  public isFavorited(topicId: number, memberId: number): Observable<string> {
    //:/{id}/favorite/member/{member}
    if (0 >= topicId) {
      return throwError('话题ID非可用值');
    }
    if (0 >= memberId) {
      return throwError('会员ID非可用值');
    }
    const headers = new HttpHeaders().set('Content-Type', 'text/plain; charset=utf-8');
    return this.http.get(this.restRequestURI + '/' + topicId + '/favorite/member/' + memberId, { headers, responseType: 'text' });
  }
  /**
   * 收藏话题
   * @param topicId 话题ID
   * @param memberId 会员ID
   * @param memberNickname 会员昵称
   * @param token 
   * @param ipAddr 
   * @returns 成功的状态码是200,失败的状态:417
   */
  public favorite(topicId: number, memberId: number, memberNickname: string, token: string, ipAddr: string): Observable<HttpResponse<string>> {
    if (0 >= topicId) {
      return throwError('话题ID非可用值');
    }
    if (0 >= memberId) {
      return throwError('暂不支持游客收藏话题');
    }
    //:/{id}/favorite
    const httpOptions = {
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded'
      }
    };
    const body = new HttpParams().set('member', memberId + '').set('nickname', memberNickname).set('token', token).set('ip', ipAddr);
    return this.http.put<HttpResponse<string>>(this.restRequestURI + '/' + topicId + '/favorite', body.toString(), httpOptions);
  }
  /**
   * 查看版块话题可用的话题类型列表. 注意版块必须与版块组(卷)是包含关系
   * @param boardGroupId 版块组ID
   * @param boardId 版块ID
   */
  public getPublishCategory(boardGroupId: number, boardId: number): Observable<ThreadsCategoryVo[]> {
    if (0 >= boardGroupId) {
      return throwError('版块组ID非可用值');
    }
    if (0 >= boardId) {
      return throwError('版块ID非可用值');
    }
    //:/category/{board}/{volume}
    return this.http.get<ThreadsCategoryVo[]>(this.restRequestURI + '/category/' + boardId + '/' + boardGroupId);
  }
  /**
   * 发布话题,非昵名形式
   * @param boardGroupId 版块组ID
   * @param boardId 版块ID
   * @param categoryId 话题类型ID,等于0等同于普通
   * @param title 标题
   * @param content 内容
   * @param memberId 会员ID
   * @param memberNickname 会员昵称
   * @param token 
   * @param ipAddr 
   * @returns 成功返回200(响应的内容是ThreadsVo),失败404(没有具体的错误描述)
   */
  public publish(
    boardGroupId: number,
    boardId: number,
    categoryId: number = 0,
    title: string,
    content: string,
    memberId: number,
    memberNickname: string,
    token: string,
    ipAddr: string): Observable<ThreadsVo> {
    if (0 >= boardGroupId) {
      return throwError('版块组ID非可用值');
    }
    if (0 >= boardId) {
      return throwError('版块ID非可用值');
    }
    if (!title || title.length == 0) {
      return throwError('话题标题非可用值');
    }
    if (!content || content.length == 0) {
      return throwError('话题内容非可用值');
    }
    if (0 > categoryId) {
      return throwError('话题类型非可用值');
    }
    if (0 >= memberId) {
      return throwError('暂不支持游客发布话题');
    }
    //:/create
    const httpOptions = {
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded'
      }
    };
    const body = new HttpParams()
      .set('volume', boardGroupId + '')
      .set('board', boardId + '')
      .set('category', categoryId + '')
      .set('title', title)
      .set('content', content)
      .set('member', memberId + '')
      .set('nickname', memberNickname)
      .set('anony', '0')
      .set('token', token)
      .set('ip', ipAddr);
    return this.http.post<ThreadsVo>(this.restRequestURI + '/create', body.toString(), httpOptions);
  }
  /**
   * 浏览话题
   * @param topicId 话题ID
   * @param memberId 会员ID
   * @param memberNickname 会员昵称
   * @param token 
   * @param ipAddr
   * @returns 成功返回200,失败417
   */
  public browse(topicId: number, memberId: number, memberNickname: string, token: string, ipAddr: string): Observable<string> {
    if (0 >= topicId) {
      return throwError('话题ID非可用值');
    }
    if (0 >= memberId) {
      return throwError('会员ID非可用值');
    }
    //:/{id}/browse
    const headers = new HttpHeaders().set('Content-Type', 'application/x-www-form-urlencoded; charset=utf-8');
    const body = new HttpParams().set('member', memberId + '').set('nickname', memberNickname).set('token', token).set('ip', ipAddr);
    return this.http.put(this.restRequestURI + '/' + topicId + '/browse', body.toString(), { headers, "responseType": "text" });
  }
  /**
   * 查看指定会员发布的所有话题,会级联加载话题统计
   * @param memberId 会员ID
   * @param page 
   * @param pageSize 
   */
  public getAllForMember(memberId: number, page: number = 1, pageSize: number = 20): Observable<EntityPageResult<ThreadsCollectStatsVo>> {
    if (0 >= memberId) {
      return throwError('会员ID非可用值');
    }
    //:/member/recent/{member}/{page}/{number}
    return this.http.get<EntityPageResult<ThreadsCollectStatsVo>>(this.restRequestURI + '/member/recent/' + memberId + '/' + page + '/' + pageSize);
  }
  /**
   * 查看会员回复的话题,话题的作者不是该会员(不包含自已发的),会级联加载话题的统计
   * @param memberId 会员ID
   * @param page 
   * @param pageSize 
   */
  public getAllForMemberReply(memberId: number, page: number = 1, pageSize: number = 20): Observable<EntityPageResult<ThreadsCollectStatsVo>> {
    if (0 >= memberId) {
      return throwError('会员ID非可用值');
    }
    //:/member/reply/{member}/{page}/{number}
    return this.http.get<EntityPageResult<ThreadsCollectStatsVo>>(this.restRequestURI + '/member/reply/' + memberId + '/' + page + '/' + pageSize);
  }
  /**
   * 从地址(/topic/:constr)中提取相关主键
   * @param constr 
   */
  public parseConString(constr: string | null): number[] {
    if (typeof constr != 'undefined' && constr) {
      let x: string[] = constr.replace('.xhtml', '').replace('/topic/', '').split('-');
      if (x.length != 3) { return []; }
      return x.map((ele: string) => parseInt(ele) ?? 0);
    }
    return [];
  }
  /**
   * 删除会员的收藏记录
   * @param topicId 话题ID
   * @param memberId 
   * @param memberNickname 
   * @param token 
   * @param ipAddr 
   */
  public cancelFavorite(topicId: number, memberId: number, memberNickname: string, token: string, ipAddr: string): Observable<HttpResponse<string>> {
    if (0 >= topicId) {
      return throwError('话题ID非可用值');
    }
    if (0 >= memberId) {
      return throwError('会员ID非可用值');
    }
    //:/{id}/favorite
    const httpOptions = {
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded'
      }
    };
    const body = new HttpParams().set('member', memberId + '').set('nickname', memberNickname).set('token', token).set('ip', ipAddr);
    return this.http.put<HttpResponse<string>>(this.restRequestURI + '/' + topicId + '/favorite/cancel', body.toString(), httpOptions);
  }
  /**
   * 删除会员的点赞记录
   * @param topicId 话题ID
   * @param memberId 
   * @param memberNickname 
   * @param token 
   * @param ipAddr 
   */
  public cancelLike(topicId: number, memberId: number, memberNickname: string, token: string, ipAddr: string): Observable<HttpResponse<string>> {
    if (0 >= topicId) {
      return throwError('话题ID非可用值');
    }
    if (0 >= memberId) {
      return throwError('会员ID非可用值');
    }
    //:/{id}/favorite
    const httpOptions = {
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded'
      }
    };
    const body = new HttpParams().set('member', memberId + '').set('nickname', memberNickname).set('token', token).set('ip', ipAddr);
    return this.http.put<HttpResponse<string>>(this.restRequestURI + '/' + topicId + '/like/cancel', body.toString(), httpOptions);
  }
  /**
   * 查看指定话题相关的话题
   * @param topicId 话题ID
   * @param showSize 
   */
  public getRelated(topicId: number, showSize: number = 10): Observable<ThreadsTagRelateVo[]>{
    if (0 >= topicId) {
      return throwError('话题ID非可用值');
    }
    if (0 >= showSize) {
      return throwError('显示数量非可用值');
    }
    let params = new HttpParams().append('size', showSize + '');
    return this.http.get<ThreadsTagRelateVo[]>(this.restRequestURI + '/' + topicId + '/relate', { params: params });
  }
  /**
   * 联合检查:
   *  1)是否可以收藏, 可以返回true
   *  2)是否可以点赞, 可以返回true
   * @param topicId 话题ID
   * @param memberId 会员ID
   */
  public getSSEUnionCheckResult(topicId: number, memberId: number): Observable<ThreadsUnionCheckVo> {
    if (0 >= memberId) {
      return throwError('不支持游客');
    }
    if (0 >= topicId) {
      return throwError('话题ID非可用值');
    }
    //:/{id}/check/{member}/operate
    const url: string = this.restRequestURI + '/' + topicId + '/check/'+ memberId+'/operate';
    return new Observable<ThreadsUnionCheckVo>(observer => {
      const eventSource = new EventSource(url);
      eventSource.addEventListener('ThreadsUnionCheck', (evt: any) => {
        observer.next(JSON.parse(evt.data) as ThreadsUnionCheckVo);
      });
      
      eventSource.addEventListener('error', (event) => {
        if (event.eventPhase == EventSource.CLOSED) {
          eventSource.close();
          console.log("[unionCheckThreads]REST Event Source Closed");
        }else{
          observer.error(event);
        }

      });
      //关闭了无法继续接受值
      return () => eventSource.close();
    });
  }
}
